<html>
    <head>
        <title>GUID生成</title>
    </head>
    <body>
        <script>
            // GUID生成

                /*
                    GUID是数据库管理系统中常用的主键类型。

                    ABP更喜欢GUID作为预构建的应用程序模块的主键。

                    此外，ICurrentUser.Id属性（参见）是GUID的类型，这意味着ABP假定用户ID始终是GUID。
                */

                /*
                    一、为什么倾向于使用GUID 作为主键？

                          GUID有优点也有缺点。你可以在网络上找到许多与此主题相关的文章，因此我们将不再全部讨论，而是列出最基本的优点：

                          它在所有数据库提供程序中都是可用的。

                          它允许在客户端确定主键，而不需要数据库往返来生成Id值。在向数据库插入新记录时，这可以提高性能，并允许我们在与数据库交互之前知道PK。

                          GUID是自然唯一的，在以下情况下具有一些优势，如果：

                                ①、你需要集成到外部系统。

                                ②、你需要拆分或合并不同的表。

                                ③、你正在创建分布式系统。

                         GUID是不可能猜测的，因此在某些情况下，与自动递增Id值相比，它们可以更安全。


                         虽然有一些缺点（只需在网络上搜索），但我们发现这些优点在设计ABP时更加重要。
                */

                /*
                    二、IGuidGenerator接口

                           GUID最重要的问题是"它默认不是顺序的"。

                           当你使用GUID作为主键并将其设置为表的"聚集索引"时，它会在插入时带来严重的性能问题（因为插入新即可能需要重新排序现有记录）。

                           因此，永远 不要使用 Guid.NewGuid() 来为你的实体创建 Ids!!

                           这个问题的很好的解决方案是生成顺序 Guid，这是由ABP开箱即用的提供的。

                           IGuidGenerator 服务创建顺序 Guid （默认由 SequentialGuidGenerator 实现）。

                           当你需要手动设置实体的ID时，请使用 IGuidGenerator.Create().

                           eg:  具有Guid主键的实体并创建该实体

                                假设你有一个具有Guid键的Product实体：

                                    using System;
                                    using Volo.Abp.Domain.Entities;

                                    namespace AbpDemo
                                    {
                                        public class Product : AggregateRoot<Guid>
                                        {
                                            public string Name { get; set; }

                                            private Product() { // }

                                            public Product(Guid id, string name)
                                                : base(id)
                                            {
                                                Name = name;
                                            }
                                        }
                                    }  
                                        
                                并且你想创建一个新产品：

                                    using System;
                                    using System.Threading.Tasks;
                                    using Volo.Abp.DependencyInjection;
                                    using Volo.Abp.Domain.Repositories;
                                    using Volo.Abp.Guids;

                                    namespace AbpDemo
                                    {
                                        public class MyProductService : ITransientDependency
                                        {
                                            private readonly IRepository<Product, Guid> _productRepository;
                                            private readonly IGuidGenerator _guidGenerator;

                                            public MyProductService(
                                                IRepository<Product, Guid> productRepository,
                                                IGuidGenerator guidGenerator)
                                            {
                                                _productRepository = productRepository;
                                                _guidGenerator = guidGenerator;
                                            }
                                            
                                            public async Task CreateAsync(string productName)
                                            {
                                                var product = new Product(_guidGenerator.Create(), productName);

                                                await _productRepository.InsertAsync(product);
                                            }
                                        }
                                    }

                                此服务在构造函数中注入IGuidGenerator。

                                如果你的类是"应用程序服务"或 "派生自其他基类之一"，你可以直接使用 "GuidGeneratorbase属性",该属性是预注入的IGuidGenerator实例。
                */

                /*
                    三、选项类  AbpSequentialGuidGeneratorOptions

                            AbpSequentialGuidGeneratorOptions是选项类，用于配置顺序GUID生成。
                            
                            它有一个属性：

                                  DefaultSequentialGuidType（enum类型为SequentialGuidType）：生成GUID值时使用的策略。   
                                  
                            数据库提供程序在处理GUID时的行为不同，因此你应该根据你的数据库提供程序进行设置。
                            
                            SequentialGuidType具有以下enum成员：

                                    ①、SequentialAtEnd（默认）适用于SQL服务器。

                                    ②、SequentialAsString由MySQL和PostgreSQL使用。

                                    ③、SequentialAsBinary由Oracle使用。


                            在模块的ConfigureServices方法中配置此选项，如下所示：

                                    Configure<AbpSequentialGuidGeneratorOptions>(options =>
                                    {
                                        options.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;
                                    });

                            EF Core集成包将此选项设置为相关DBMS的正确值。因此，大多数时候，如果你使用这些集成包，则不需要设置此选项。
                */
        </script>
    </body>
</html>